#include <mockcpp/mockcpp.hpp>
#include <testngpp/testngpp.hpp>
#include "Length.h"
#include "Formater.h"


USING_MOCKCPP_NS
USING_TESTNGPP_NS


namespace
{
    bool isLengthOutExpected(const Length& length, const Formater& formater, const char* expect)
    {
        std::ostringstream ost;
        ost << length << formater;
        return (ost.str() == std::string(expect));
    }
    
    bool isExpectedLengthOutInSeqUnit(const Length& length, const char* expect)
    {
        return isLengthOutExpected(length, SequenceUnitFormater(), expect);
    }

    bool isExpectedLengthOutInBaseUnit(const Length& length, const char* expect)
    {
        return isLengthOutExpected(length, BaseUnitFormater(), expect);
    }
}


FIXTURE(Length_compare)
{
    TEST(Feet(1) == Feet(1))
    {
        ASSERT_TRUE(Length(1, FEET) == Length(1, FEET));
    }

    TEST(Feet(1) != Feet(2))
    {
        ASSERT_TRUE(Length(1, FEET) != Length(2, FEET));
    }

    TEST(Yard(1) == Yard(1))
    {
        ASSERT_TRUE(Length(1, YARD) == Length(1, YARD));
    }

    TEST(Yard(1) != Yard(2))
    {
        ASSERT_TRUE(Length(1, YARD) != Length(2, YARD));
    }
    
    TEST(Mile(1) == Mile(1))
    {
        ASSERT_TRUE(Length(1, MILE) == Length(1, MILE));
    }

    TEST(Mile(1) != Mile(2))
    {
        ASSERT_TRUE(Length(1, MILE) != Length(2, MILE));
    }

    TEST(Feet(3) == Yard(1))
    {
        ASSERT_TRUE(Length(3, FEET) == Length(1, YARD));
    }
    
    TEST(Feet(3*1760) == Mile(1))
    {
        ASSERT_TRUE(Length(3*1760, FEET) == Length(1, MILE));
    }
    
    TEST(Yard(1760) == Mile(1))
    {
        ASSERT_TRUE(Length(1760, YARD) == Length(1, MILE));
    }
};

FIXTURE(Length_plus)
{
    TEST(Feet(1) + Feet(1) == Feet(2))
    {
        ASSERT_TRUE((Length(1, FEET) + Length(1, FEET)) == Length(2, FEET));
    }

    TEST(Yard(1) + Yard(1) == Yard(2))
    {
        ASSERT_TRUE((Length(1, YARD) + Length(1, YARD)) == Length(2, YARD));
    }

    TEST(Mile(1) + Mile(1) == Mile(2))
    {
        ASSERT_TRUE((Length(1, MILE) + Length(1, MILE)) == Length(2, MILE));
    }

    TEST(Feet(1) + Yard(1) == Feet(4))
    {
        ASSERT_TRUE((Length(1, FEET) + Length(1, YARD)) == Length(4, FEET));
    }
    
    TEST(Feet(1) + Mile(1) == Feet(1760*3+1))
    {
        ASSERT_TRUE((Length(1, FEET) + Length(1, MILE)) == Length(1760*3+1, FEET));
    }

    TEST(Yard(1) + Mile(1) == Yard(1761))
    {
        ASSERT_TRUE((Length(1, YARD) + Length(1, MILE)) == Length(1761, YARD));
    }
};

FIXTURE(LengthOut_InSequenceUnit)
{   
    TEST(Length(5280, Feet) outputs "1 MILE")
    {
        Length length(5280, FEET);
        ASSERT_TRUE(isExpectedLengthOutInSeqUnit(length, "1 MILE"));
    }

    TEST(Length(3, Feet) outputs "1 YARD")
    {
        Length length(3, FEET);
        ASSERT_TRUE(isExpectedLengthOutInSeqUnit(length, "1 YARD"));
    }
    TEST(Length(2, Feet) outputs "2 FEET")
    {
        Length length(2, FEET);
        ASSERT_TRUE(isExpectedLengthOutInSeqUnit(length, "2 FEET"));
    }
    TEST(Length(5281, Feet) outputs "1 MILE 1 FEET")
    {
        Length length(5281, FEET);
        ASSERT_TRUE(isExpectedLengthOutInSeqUnit(length, "1 MILE 1 FEET"));
    }
    TEST(Length(10, Feet) outputs "3 YARD 1 FEET")
    {
        Length length(10, FEET);
         ASSERT_TRUE(isExpectedLengthOutInSeqUnit(length, "3 YARD 1 FEET"));
    }
    TEST(Length(1761, Yard) outputs "1 MILE 1 YARD")
    {
        Length length(1761, YARD);
         ASSERT_TRUE(isExpectedLengthOutInSeqUnit(length, "1 MILE 1 YARD"));
    }
    TEST(Length(0, Feet) outputs "0 FEET")
    {
        Length length(0, FEET);
         ASSERT_TRUE(isExpectedLengthOutInSeqUnit(length, "0 FEET"));
    }

};

FIXTURE(LengthOut_InBaseUnit)
{   
    TEST(Length(5280, Feet) outputs "1 MILE")
    {
        Length length(5280, FEET);
        ASSERT_TRUE(isExpectedLengthOutInBaseUnit(length, "1 MILE"));
    }
    TEST(Length(3, Feet) outputs "1 YARD")
    {
        Length length(3, FEET);
        ASSERT_TRUE(isExpectedLengthOutInBaseUnit(length, "1 YARD"));
    }
    TEST(Length(2, Feet) outputs "2 FEET")
    {
        Length length(2, FEET);
        ASSERT_TRUE(isExpectedLengthOutInBaseUnit(length, "2 FEET"));
    }
    TEST(Length(5281, Feet) outputs "5281 FEET")
    {
        Length length(5281, FEET);
        ASSERT_TRUE(isExpectedLengthOutInBaseUnit(length, "5281 FEET"));
    }
    TEST(Length(10, Feet) outputs "10 FEET")
    {
        Length length(10, FEET);
        ASSERT_TRUE(isExpectedLengthOutInBaseUnit(length, "10 FEET"));
    }
    TEST(Length(1761, Yard) outputs "1761 FEET")
    {
        Length length(1761, YARD);
        ASSERT_TRUE(isExpectedLengthOutInBaseUnit(length, "1761 FEET"));
    }
    TEST(Length(0, Feet) outputs "0 FEET")
    {
        Length length(0, FEET);
        ASSERT_TRUE(isExpectedLengthOutInBaseUnit(length, "0 FEET"));
    }
};


